// Capitalize类型，让属性名名首字母大写
type Customer = { username: string; age: number; 100: number }
type PropsUpper<T> = { [P in keyof T as P extends string ? Capitalize<P> : P]: T[P] }
type CustomerUpper = PropsUpper<Customer>  // type CustomerUpper = { Username: string; Age: number; 100: number }

// 用 重映射类型，实现左侧遍历属性，右侧用extends泛型约束过去出目标属性，再用Capitalize与模板字符类型实现方法名重写
// 需求：筛选出方法。并且更改方法名，将 add 改为 doAdd
interface Todo {
  title: string;
  completed: boolean;
  description: string;
  add(): number;
  // add: () => number;  // 等价于
  del(): number;
  update(): number;
}

// 1、获取Todo 函数
type Degree<T> = {
  [P in keyof T as T[P] extends Function ? P : never]: T[P]
}
type DegreeTodo = Degree<Todo>  // type DegreeTodo = { add: () => number; ... }

// 2、为方法名添加do，用Capitalize实现首字母大写
type Degree2<T extends Record<string, any>> = {
  [P in keyof T as T[P] extends Function ? `do${Capitalize<P & string>}` : never]: T[P]
} 
type DegreeTodo2 = Degree2<Todo>  // type DegreeTodo2 = { doAdd: ()=> number; ... }

// 3、限制数组类型作为泛型参数类型传递进去。
// 方案1、新增一个条件类型来限制
type Degree3<T extends Record<string, any>> = T extends Array<any> ? never : {
  [P in keyof T as T[P] extends Function ? `do${Capitalize<P & string>}` : never]: T[P]
}
type DegreeTodo3 = Degree3<Array<any>>  // type DegreeTodo2 = never

// 方案2、在条件类型中，对 T 进行类型约束
type ExcludeArr<T> = Exclude<T, Array<any>>
type Degree4<T extends Record<string, any>> = {
  [P in keyof ExcludeArr<T> as ExcludeArr<T>[P] extends Function ? `do${Capitalize<P & string>}` : never]: ExcludeArr<T>[P]
}
type DegreeTodo4 = Degree4<Array<any>>  // type DegreeTodo2 = {}

export {}